package io.github.kimmking.kkconfig.server;

import io.github.kimmking.kkconfig.server.dal.LocksMapper;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.Getter;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Distributed locks.
 *
 * @Author : kimmking(kimmking@apache.org)
 * @create 2024/4/24 上午3:32
 */
@Component
public class DistLocks {

    @Autowired
    LocksMapper locksMapper;

//    @Autowired
//    private DataSourceTransactionManager dataSourceTransactionManager;
//    TransactionStatus transaction = null;

    @Autowired
    private DataSource dataSource;

    private Connection connection;

    @Getter
    private AtomicBoolean locked = new AtomicBoolean(false);
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    @PostConstruct
    public void init() {
        try {
            connection = dataSource.getConnection();
        } catch (SQLException e) {
            System.out.println("get connection failed.");
            throw new RuntimeException(e);
        }
        executor.scheduleAtFixedRate(this::tryLock, 1000, 5000, TimeUnit.MILLISECONDS);
    }

    private void tryLock() {
        try {
            lock();
            locked.set(true);
        } catch (Exception ex) {
            //ex.printStackTrace();
            System.out.println(" ====>> get a dist lock failed.");
            locked.set(false);
            //close();
        }
    }

    @SneakyThrows
    public boolean lock() {
//            DefaultTransactionDefinition df = new DefaultTransactionDefinition();
//            df.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
//            transaction = dataSourceTransactionManager.getTransaction(df);
//        // todo 定时调度，5s 执行一次。
//        locksMapper.waitTime();
//        return locksMapper.selectForUpdate().equals("kkconfig-server");

        connection.setAutoCommit(false);
        connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
        connection.createStatement().execute("set innodb_lock_wait_timeout=5");
        connection.createStatement().execute("select app from locks where id = 1 for update");

        if(locked.get())
            System.out.println(" ====>> reenter a dist lock.");
        else
            System.out.println(" ====>> get a dist lock.");

        return true;
    }

    @PreDestroy
    public void close() {

        try {
            if(connection != null && !connection.isClosed()) {
                connection.rollback();
                connection.close();
            }
        } catch (SQLException e) {
            //e.printStackTrace();
            System.out.println("close connection failed.");
        }


//        if(transaction == null) return;
//        try {
//            dataSourceTransactionManager.commit(transaction);
//        }catch (Exception e){
//            //e.printStackTrace();
//            dataSourceTransactionManager.rollback(transaction);
//        }
    }

}
